/*
 * main.c
 *
 *  Created on: Jan 16, 2014
 *      Author: adijoshi
 */

#include "includes.h"

int DONE;
FILE *TRACE;
int single_step_i;
char optional_display;
FILE *B_TRACE;

int main(void)
{
	init();
	run();

	printf("\n  Press a key to exit ... ");
	fflush(stdin);
	getchar();
	if(single_step_i) {
		fflush(stdin);
		getchar();
	}
	return 0;
}

void init(void)
{
	unsigned short address;
	char filename[200];
	char choice_c;
	int choice_i;

	printf("\n  Enter ascii file name to simulate : ");
	fflush(stdin);
	scanf("%s", filename);

	/*
	 * this code initializes valid / invalid mem locations
	 * code starts
	 */
	unsigned short _index =0;
	for(_index=0; _index<WORDS; _index++)
		//MemStatus[_index*2] = INVALID_MEM_LOCATION;
		set_memory_status(INVALID_MEM_LOCATION,_index*2);
	/*
	 *  code ends
	 */

	parse_ascii(filename);

	printf("\n  Done code writing to memory.");
	printf("\n");

	fflush(stdin);
	printf("\n  Enter value to be loaded in PC (in octal format) : ");
	scanf("%o", (unsigned int *)&address);
	write_in_memory(PC,address,DATA);

	fflush(stdin);
	printf("\n  Stack pointer defaults to (octal) 160000");
	printf("\n  Do you wish to change stack pointer as well (y/n)? : ");
	fflush(stdin);
	choice_c = getchar();
	choice_c = getchar();

	choice_i = (int)choice_c;
	if (choice_i == (int)'y' || choice_i == (int)'Y') {
		printf("\n  Enter value to be loaded in SP (in octal format) : ");
		scanf("%o", (unsigned int *)&address);
		write_in_memory(SP,address,DATA);
	} else {
		write_in_memory(SP,0160000,DATA);
	}
}

void run(void)
{
	unsigned char single_step_c;

	unsigned short instruction;

	int inst_count = 0;

	TRACE = fopen("trace.txt","w");
	B_TRACE = fopen("branch_trace.txt","w");
	fprintf(B_TRACE,"\n");
	fprintf(B_TRACE," Branch\t\tType of branch\t\tPC\t\t\tTarget PC\tBranch result");
	fprintf(B_TRACE,"\n----------------------------------------------------------------------");
	fprintf(B_TRACE,"\n");

	printf("\n  Do you wish to simulate in single step mode (y/n)? : ");
	fflush(stdin);
	single_step_c = getchar();
	single_step_c = getchar();

	single_step_i = (int)single_step_c;
	printf("\n");

	if (single_step_i != (int)'y' && single_step_i != (int)'Y')
	{
		printf("\n  Do you wish to switch ON display of Registers and NZCV flags (y/n)? : ");
		fflush(stdin);
		optional_display = getchar();
		optional_display = getchar();
	}
	else
	{
		optional_display = 'y';
	}

	printf(" --------------------------------------------------------- \n");
	while(!DONE) {
		fflush(stdin);
		inst_count++;

		instruction = fetch_instruction();
		set_Program_Counter(get_Program_Counter() + 2);

		decode_instruction(instruction);

	/*	-- delete if works
	 *
	 * if(optional_display == 'y' || optional_display == 'Y')
		{
			printf("\n");
			printf("\n  Instruction : %.6o", instruction);
			print_contents();
			print_mem_loc();
		}*/

		if (single_step_i == (int)'y' || single_step_i == (int)'Y') {

			printf("\n");
			printf("\n  Instruction : %.6o", instruction);
			print_contents();
			print_mem_loc();

			printf("\n  Press a key to continue ... ");
			fflush(stdin);
			getchar();
			if(inst_count == 1) {
				fflush(stdin);
				getchar();
			}
			if(optional_display == 'y' || optional_display == 'Y')
				printf(" --------------------------------------------------------- \n");
		}
		/*else
			if(optional_display == 'y' || optional_display == 'Y')
				printf(" --------------------------------------------------------- \n");*/
	}

	if (single_step_i != (int)'y' && single_step_i != (int)'Y')
		if(optional_display == 'y' || optional_display == 'Y')
		{
			print_contents();
			print_mem_loc();
		}


	printf("\n  Executed %d instructions.",inst_count);
	printf("\n");
	fflush(TRACE);
	fclose(TRACE);
	fflush(B_TRACE);
	fclose(B_TRACE);
}

unsigned short fetch_instruction(void)
{
	unsigned short PC_val = get_Program_Counter();
	//printf("\n  Instruction fetched from address : %.6o", PC_val);
	if(check_boundary_error(PC_val))
	{
		printf("\n  Error : Attempt to fetch instruction from an odd address.");
		exit_on_error();
		//printf("\n");
	}

	return read_from_memory(PC_val,INSTRUCTION);

}
